/**
 * Copyright(c) 2010 Jade Techonologies Co., Ltd.
 *
 * History:
 *   13-5-19 下午1:19 Created by lyyang
 */
package com.jade.framework.web.security;

import java.lang.reflect.Method;
import java.security.Permission;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.jade.framework.base.security.AbstractPrincipal;
import com.jade.framework.base.security.PermissionService;
import com.jade.framework.web.controller.ControllerUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * 权限拦截器
 *
 * @author lyyang
 * @version 1.0 13-5-19 下午1:19
 */
public class PermissionInterceptor
        extends HandlerInterceptorAdapter
{
    private String ajaxNoPermissionUrl;
    private String noPermissionUrl;
    private String notLoginUrl;
    private String ajaxNotLoginUrl;
    private PermissionService permissionService;
    private Log log = LogFactory.getLog(PermissionInterceptor.class);

    public String getAjaxNoPermissionUrl()
    {
        return ajaxNoPermissionUrl;
    }

    public void setAjaxNoPermissionUrl(String ajaxNoPermissionUrl)
    {
        this.ajaxNoPermissionUrl = ajaxNoPermissionUrl;
    }

    public String getNoPermissionUrl()
    {
        return noPermissionUrl;
    }

    public String getNotLoginUrl()
    {
        return notLoginUrl;
    }

    public void setNotLoginUrl(String notLoginUrl)
    {
        this.notLoginUrl = notLoginUrl;
    }

    public void setNoPermissionUrl(String noPermissionUrl)
    {
        this.noPermissionUrl = noPermissionUrl;
    }

    public String getAjaxNotLoginUrl()
    {
        return ajaxNotLoginUrl;
    }

    public void setAjaxNotLoginUrl(String ajaxNotLoginUrl)
    {
        this.ajaxNotLoginUrl = ajaxNotLoginUrl;
    }

    @Inject
    public void setPermissionService(@Named ("system_permissionService") PermissionService permissionService)
    {
        this.permissionService = permissionService;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception
    {
        Method method = ((HandlerMethod) handler).getMethod();

        CheckPermission checkPermission = method.getAnnotation(CheckPermission.class);
        if (checkPermission != null) {
            RequestMapping mapping = method.getAnnotation(RequestMapping.class);
            String mappingUrl[] = mapping.value();
            if (mappingUrl != null && mappingUrl.length > 0 && mappingUrl[0].indexOf("{id}") > 0) {
                String strUrl = request.getRequestURI();
                String[] url = strUrl.split("/");
                String[] mappings = mappingUrl[0].split("/");
                int offset = url.length - mappings.length;
                for (int i = 0; i < mappings.length; i++) {
                    if (mappings[i].equalsIgnoreCase("{id}")) {
                        request.setAttribute("id", url[i + offset]);
                    }
                }

            }

            boolean ajaxReturn = ControllerUtils.isAjaxReturn(method);

            String path = request.getContextPath();
            if (!path.endsWith("/")) {
                path += "/";
            }
            AbstractPrincipal userInfo = (AbstractPrincipal) request.getUserPrincipal();

            //判断是否是通过token方式登录的用户
            if (userInfo == null) {
                HttpSession session = request.getSession();
                if (session != null) {
                    userInfo = (AbstractPrincipal) session.getAttribute("principal");
                }
            }

            if (userInfo == null) {
                if (ajaxReturn) {
                    response.sendRedirect(path + ajaxNotLoginUrl);
                }
                else {
                    response.sendRedirect(path + notLoginUrl);
                }
                return false;
            }
            if (userInfo.isSuperman()) {
                return true;
            }
            String[] strPermissions = checkPermission.permission();
            if (strPermissions == null || strPermissions.length == 0) {
                return true;
            }

            boolean isHavePermission;
            Permission[] permissions = new Permission[strPermissions.length];
            for (int i = 0; i < strPermissions.length; i++) {
                permissions[i] = permissionService.getPermission(strPermissions[i]);
            }
            if (checkPermission.mode() == CheckPermission.MODE_OR) {
                isHavePermission = checkORPermission(request, permissions);
            }
            else {
                isHavePermission = checkADDPermission(request, permissions);
            }
            if (!isHavePermission) {
                if (ajaxReturn) {
                    response.sendRedirect(path + ajaxNoPermissionUrl);
                }
                else {
                    response.sendRedirect(path + noPermissionUrl);
                }
                return false;
                //                throw new BssPermissionException("err.module.aop.permission", null, "html");
            }
        }
        return super.preHandle(request, response, handler);
    }


    private boolean checkADDPermission(HttpServletRequest request, Permission[] permissions)
    {
        for (Permission permission : permissions) {
            try {
                permission.checkGuard(request);
            }
            catch (SecurityException ex) {
                log.error(ex.getMessage());
                return false;
            }
        }
        return true;
    }

    private boolean checkORPermission(HttpServletRequest request, Permission[] permissions)
    {
        for (Permission permission : permissions) {
            try {
                permission.checkGuard(request);
                return true;
            }
            catch (SecurityException ex) {
                log.error(ex.getMessage());
            }
        }
        return false;
    }
}
